/* CoralCube | Massively Multiplayer Online Role-Playing Game(MMORPG) Emulator.
|* 
|* Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/>
|*               2008-2010 TrinityCore <http://www.trinitycore.org/>
|*               2008-2010 CoralCube <http://www.CoralCube.com/>
|*
|* This program is free software. You can redistribute it and/or modify it under the terms of 
|* the GNU General Public License as published by the Free Software Foundation, either 
|* version 2 of the License.
|*
|* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY, 
|* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
|* See the GNU General Public License for more details.
|*
|* You should have received a copy of the GNU General Public License along with this program. 
|* If not, see <http://www.gnu.org/licenses/>.
|*/

#ifndef RIBONCORE_CREATURE_H
#define RIBONCORE_CREATURE_H

#include "Common.h"
#include "Unit.h"
#include "UpdateMask.h"
#include "ItemPrototype.h"
#include "LootMgr.h"
#include "DatabaseEnv.h"
#include "Cell.h"

#include <list>

struct SpellEntry;

class CreatureAI;
class Quest;
class Player;
class WorldSession;
class CreatureGroup;

enum CreatureFlagsExtra
{
    CREATURE_FLAG_EXTRA_INSTANCE_BIND   = 0x00000001,       // creature kill bind instance with killer and killer's group
    CREATURE_FLAG_EXTRA_CIVILIAN        = 0x00000002,       // not aggro (ignore faction/reputation hostility)
    CREATURE_FLAG_EXTRA_NO_PARRY        = 0x00000004,       // creature can't parry
    CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN = 0x00000008,       // creature can't counter-attack at parry
    CREATURE_FLAG_EXTRA_NO_BLOCK        = 0x00000010,       // creature can't block
    CREATURE_FLAG_EXTRA_NO_CRUSH        = 0x00000020,       // creature can't do crush attacks
    CREATURE_FLAG_EXTRA_NO_XP_AT_KILL   = 0x00000040,       // creature kill not provide XP
    CREATURE_FLAG_EXTRA_TRIGGER         = 0x00000080,       // trigger creature
    CREATURE_FLAG_EXTRA_NO_TAUNT        = 0x00000100,       // creature is immune to taunt auras and effect attack me
    CREATURE_FLAG_EXTRA_WORLDEVENT      = 0x00004000,       // custom flag for world event creatures (left room for merging)
    //CREATURE_FLAG_EXTRA_CHARM_AI        = 0x00008000,       // use ai when charmed
    CREATURE_FLAG_EXTRA_NO_CRIT         = 0x00020000,       // creature can't do critical strikes
    CREATURE_FLAG_EXTRA_NO_SKILLGAIN    = 0x00040000,       // creature won't increase weapon skills
    CREATURE_FLAG_EXTRA_TAUNT_DIMINISH  = 0x00080000,       // Taunt is a subject to diminishing returns on this creautre
    CREATURE_FLAG_EXTRA_ALL_DIMINISH    = 0x00100000,       // Creature is subject to all diminishing returns as player are
};

// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform
#if defined(__GNUC__)
#pragma pack(1)
#else
#pragma pack(push,1)
#endif

#define MAX_KILL_CREDIT 2
#define CREATURE_REGEN_INTERVAL 2 * IN_MILLISECONDS

#define MAX_CREATURE_QUEST_ITEMS 6

// from `creature_template` table
struct CreatureInfo
{
    uint32  Entry;
    uint32  DifficultyEntry[MAX_DIFFICULTY - 1];
    uint32  KillCredit[MAX_KILL_CREDIT];
    uint32  Modelid1;
    uint32  Modelid2;
    uint32  Modelid3;
    uint32  Modelid4;
    char*   Name;
    char*   SubName;
    char*   IconName;
    uint32  GossipMenuId;
    uint8   minlevel;
    uint8   maxlevel;
    uint32  expansion;
    uint32  faction_A;
    uint32  faction_H;
    uint32  npcflag;
    float   speed_walk;
    float   speed_run;
    float   scale;
    uint32  rank;
    float   mindmg;
    float   maxdmg;
    uint32  dmgschool;
    uint32  attackpower;
    float   dmg_multiplier;
    uint32  baseattacktime;
    uint32  rangeattacktime;
    uint32  unit_class;                                     // enum Classes. Note only 4 classes are known for creatures.
    uint32  unit_flags;                                     // enum UnitFlags mask values
    uint32  dynamicflags;
    uint32  family;                                         // enum CreatureFamily values (optional)
    uint32  trainer_type;
    uint32  trainer_spell;
    uint32  trainer_class;
    uint32  trainer_race;
    float   minrangedmg;
    float   maxrangedmg;
    uint32  rangedattackpower;
    uint32  type;                                           // enum CreatureType values
    uint32  type_flags;                                     // enum CreatureTypeFlags mask values
    uint32  lootid;
    uint32  pickpocketLootId;
    uint32  SkinLootId;
    int32   resistance1;
    int32   resistance2;
    int32   resistance3;
    int32   resistance4;
    int32   resistance5;
    int32   resistance6;
    uint32  spells[CREATURE_MAX_SPELLS];
    uint32  PetSpellDataId;
    uint32  VehicleId;
    uint32  mingold;
    uint32  maxgold;
    char const* AIName;
    uint32  MovementType;
    uint32  InhabitType;
    float   ModHealth;
    float   ModMana;
    float   ModArmor;
    bool    RacialLeader;
    uint32  questItems[MAX_CREATURE_QUEST_ITEMS];
    uint32  movementId;
    bool    RegenHealth;
    uint32  equipmentId;
    uint32  MechanicImmuneMask;
    uint32  flags_extra;
    uint32  ScriptID;
    uint32  GetRandomValidModelId() const;
    uint32  GetFirstValidModelId() const;

    // helpers
    SkillType GetRequiredLootSkill() const
    {
        if (type_flags & CREATURE_TYPEFLAGS_HERBLOOT)
            return SKILL_HERBALISM;
        else if (type_flags & CREATURE_TYPEFLAGS_MININGLOOT)
            return SKILL_MINING;
        else if (type_flags & CREATURE_TYPEFLAGS_ENGINEERLOOT)
            return SKILL_ENGINERING;
        else
            return SKILL_SKINNING;                          // normal case
    }

    bool isTameable(bool exotic) const
    {
        if (type != CREATURE_TYPE_BEAST || family == 0 || (type_flags & CREATURE_TYPEFLAGS_TAMEABLE) == 0)
            return false;

        // if can tame exotic then can tame any temable
        return exotic || (type_flags & CREATURE_TYPEFLAGS_EXOTIC) == 0;
    }
};

// Represents max amount of expansions.
// TODO: Add MAX_EXPANSION constant.
#define MAX_CREATURE_BASE_HP 3

// Defines base stats for creatures (used to calculate HP/mana/armor).
struct CreatureBaseStats
{
    uint32 BaseHealth[MAX_CREATURE_BASE_HP];
    uint32 BaseMana;
    uint32 BaseArmor;

    // Helpers

    uint32 GenerateHealth(CreatureInfo const* info) const
    {
        return uint32((BaseHealth[info->expansion] * info->ModHealth) + 0.5f);
    }

    uint32 GenerateMana(CreatureInfo const* info) const
    {
        // Mana can be 0.
        if (!BaseMana)
            return 0;

        return uint32((BaseMana * info->ModMana) + 0.5f);
    }

    uint32 GenerateArmor(CreatureInfo const* info) const
    {
        return uint32((BaseArmor * info->ModArmor) + 0.5f);
    }

    static CreatureBaseStats const* GetBaseStats(uint8 level, uint8 unitClass);
};

typedef UNORDERED_MAP<uint16, CreatureBaseStats> CreatureBaseStatsMap;

struct CreatureLocale
{
    StringVector Name;
    StringVector SubName;
};

struct GossipMenuItemsLocale
{
    StringVector OptionText;
    StringVector BoxText;
};

struct PointOfInterestLocale
{
    StringVector IconName;
};

struct EquipmentInfo
{
    uint32  entry;
    uint32  equipentry[3];
};

// from `creature` table
struct CreatureData
{
    explicit CreatureData() : dbData(true) { }
    uint32 id;                                              // entry in creature_template
    uint16 mapid;
    uint16 phaseMask;
    uint32 displayid;
    int32 equipmentId;
    float posX;
    float posY;
    float posZ;
    float orientation;
    uint32 spawntimesecs;
    float spawndist;
    uint32 currentwaypoint;
    uint32 curhealth;
    uint32 curmana;
    bool  is_dead;
    uint8 movementType;
    uint8 spawnMask;
    uint32 npcflag;
    uint32 unit_flags;                                      // enum UnitFlags mask values
    uint32 dynamicflags;
    bool dbData;
};

struct CreatureDataAddonAura
{
    uint32 spell_id;
    uint8 effectMask;
};

// from `creature_addon` table
struct CreatureDataAddon
{
    uint32 guidOrEntry;
    uint32 path_id;
    uint32 mount;
    uint32 bytes1;
    uint32 bytes2;
    uint32 emote;
    CreatureDataAddonAura const* auras;                     // loaded as char* "spell1 eff1 spell2 eff2 ... "
};

struct CreatureModelInfo
{
    uint32 modelid;
    float bounding_radius;
    float combat_reach;
    uint8 gender;
    uint32 modelid_other_gender;
};

enum InhabitTypeValues
{
    INHABIT_GROUND = 1,
    INHABIT_WATER  = 2,
    INHABIT_AIR    = 4,
    INHABIT_ANYWHERE = INHABIT_GROUND | INHABIT_WATER | INHABIT_AIR
};

// Enums used by StringTextData::Type (CreatureEventAI)
enum ChatType
{
    CHAT_TYPE_SAY               = 0,
    CHAT_TYPE_YELL              = 1,
    CHAT_TYPE_TEXT_EMOTE        = 2,
    CHAT_TYPE_BOSS_EMOTE        = 3,
    CHAT_TYPE_WHISPER           = 4,
    CHAT_TYPE_BOSS_WHISPER      = 5,
    CHAT_TYPE_ZONE_YELL         = 6,
    CHAT_TYPE_END               = 255
};

// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform
#if defined(__GNUC__)
#pragma pack()
#else
#pragma pack(pop)
#endif

// Vendors
struct VendorItem
{
    VendorItem(uint32 _item, int32 _maxcount, uint32 _incrtime, uint32 _ExtendedCost) : item(_item), maxcount(_maxcount), 
        incrtime(_incrtime), ExtendedCost(_ExtendedCost) { }

    uint32 item;
    uint32  maxcount;                                       // 0 for infinity item amount
    uint32 incrtime;                                        // time for restore items amount if maxcount != 0
    uint32 ExtendedCost;

    //helpers
    bool IsGoldRequired(ItemPrototype const* pProto) const { return pProto->Flags2 & ITEM_FLAGS_EXTRA_EXT_COST_REQUIRES_GOLD || !ExtendedCost; }
};
typedef std::vector<VendorItem*> VendorItemList;

struct VendorItemData
{
    VendorItemList m_items;

    VendorItem* GetItem(uint32 slot) const
    {
        if (slot >= m_items.size()) return NULL;
        return m_items[slot];
    }
    bool Empty() const { return m_items.empty(); }
    uint8 GetItemCount() const { return m_items.size(); }
    void AddItem(uint32 item, int32 maxcount, uint32 ptime, uint32 ExtendedCost)
    {
        m_items.push_back(new VendorItem(item, maxcount, ptime, ExtendedCost));
    }
    bool RemoveItem(uint32 item_id);
    VendorItem const* FindItemCostPair(uint32 item_id, uint32 extendedCost) const;
    void Clear()
    {
        for (VendorItemList::const_iterator itr = m_items.begin(); itr != m_items.end(); ++itr)
            delete (*itr);
        m_items.clear();
    }
};

struct VendorItemCount
{
    explicit VendorItemCount(uint32 _item, uint32 _count) : itemId(_item), count(_count), lastIncrementTime(time(NULL)) { }

    uint32 itemId;
    uint32 count;
    time_t lastIncrementTime;
};

typedef std::list<VendorItemCount> VendorItemCounts;

struct TrainerSpell
{
    TrainerSpell() : spell(0), spellCost(0), reqSkill(0), reqSkillValue(0), reqLevel(0)
    {
        for (uint8 i = 0; i < MAX_SPELL_EFFECTS ; ++i)
            learnedSpell[i] = 0;
    }

    uint32 spell;
    uint32 spellCost;
    uint32 reqSkill;
    uint32 reqSkillValue;
    uint32 reqLevel;
    uint32 learnedSpell[3];

    // helpers
    bool IsCastable() const { return learnedSpell[0] != spell; }
};

typedef UNORDERED_MAP<uint32 /*spellid*/, TrainerSpell> TrainerSpellMap;

struct TrainerSpellData
{
    TrainerSpellData() : trainerType(0) { }

    TrainerSpellMap spellList;
    uint32 trainerType;                                     // trainer type based at trainer spells, can be different from creature_template value.
    // req. for correct show non-prof. trainers like weaponmaster, allowed values 0 and 2.
    TrainerSpell const* Find(uint32 spell_id) const;
    void Clear() { spellList.clear(); }
};

typedef std::map<uint32,time_t> CreatureSpellCooldowns;

// max different by z coordinate for creature aggro reaction
#define CREATURE_Z_ATTACK_RANGE 3

#define MAX_VENDOR_ITEMS 150                                // Limitation in 3.x.x item count in SMSG_LIST_INVENTORY

class Creature : public Unit, public GridObject<Creature>
{
public:

    explicit Creature();
    virtual ~Creature();

    void AddToWorld();
    void RemoveFromWorld();

    void DisappearAndDie();

    bool Create(uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint32 vehId, uint32 team, float x, float y, float z, float ang, const CreatureData *data = NULL);
    bool LoadCreaturesAddon(bool reload = false);
    void SelectLevel(const CreatureInfo *cinfo);
    void LoadEquipment(uint32 equip_entry, bool force=false);

    uint32 GetDBTableGUIDLow() const { return m_DBTableGuid; }
    char const* GetSubName() const { return GetCreatureInfo()->SubName; }

    void Update(uint32 time);                         // overwrited Unit::Update
    void GetRespawnCoord(float &x, float &y, float &z, float* ori = NULL, float* dist =NULL) const;
    uint32 GetEquipmentId() const { return GetCreatureInfo()->equipmentId; }

    void SetCorpseDelay(uint32 delay) { m_corpseDelay = delay; }
    bool isRacialLeader() const { return GetCreatureInfo()->RacialLeader; }
    bool isCivilian() const { return GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_CIVILIAN; }
    bool isTrigger() const { return GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER; }
    bool canWalk() const { return GetCreatureInfo()->InhabitType & INHABIT_GROUND; }
    bool canSwim() const { return GetCreatureInfo()->InhabitType & INHABIT_WATER; }
    //bool canFly()  const { return GetCreatureInfo()->InhabitType & INHABIT_AIR; }

    void SetReactState(ReactStates st) { m_reactState = st; }
    ReactStates GetReactState() { return m_reactState; }
    bool HasReactState(ReactStates state) const { return (m_reactState == state); }
    void InitializeReactState()
    {
        if (isTotem() || isTrigger() || GetCreatureType() == CREATURE_TYPE_CRITTER || isSpiritService())
            SetReactState(REACT_PASSIVE);
        else
            SetReactState(REACT_AGGRESSIVE);
        /*else if (isCivilian())
        SetReactState(REACT_DEFENSIVE);*/;
    }

    ///// TODO RENAME THIS!!!!!
    bool isCanTrainingOf(Player* player, bool msg) const;
    bool isCanInteractWithBattleMaster(Player* player, bool msg) const;
    bool isCanTrainingAndResetTalentsOf(Player* pPlayer) const;
    bool canCreatureAttack(Unit const *pVictim, bool force = true) const;
    bool IsImmunedToSpell(SpellEntry const* spellInfo);
    // redefine Unit::IsImmunedToSpell
    bool IsImmunedToSpellEffect(SpellEntry const* spellInfo, uint32 index) const;
    // redefine Unit::IsImmunedToSpellEffect
    bool isElite() const
    {
        if (isPet())
            return false;

        uint32 rank = GetCreatureInfo()->rank;
        return rank != CREATURE_ELITE_NORMAL && rank != CREATURE_ELITE_RARE;
    }

    bool isWorldBoss() const
    {
        if (isPet())
            return false;

        return GetCreatureInfo()->rank == CREATURE_ELITE_WORLDBOSS;
    }

    uint8 getLevelForTarget(WorldObject const* target) const; // overwrite Unit::getLevelForTarget for boss level support

    bool IsInEvadeMode() const { return hasUnitState(UNIT_STAT_EVADE); }

    bool AIM_Initialize(CreatureAI* ai = NULL);
    void Motion_Initialize();

    void AI_SendMoveToPacket(float x, float y, float z, uint32 time, uint32 MovementFlags, uint8 type);
    CreatureAI * AI() const { return (CreatureAI*)i_AI; }

    uint32 GetShieldBlockValue() const                  //dunno mob block value
    {
        return (getLevel()/2 + uint32(GetStat(STAT_STRENGTH)/20));
    }

    SpellSchoolMask GetMeleeDamageSchoolMask() const { return m_meleeDamageSchoolMask; }
    void SetMeleeDamageSchool(SpellSchools school) { m_meleeDamageSchoolMask = SpellSchoolMask(1 << school); }

    void _AddCreatureSpellCooldown(uint32 spell_id, time_t end_time);
    void _AddCreatureCategoryCooldown(uint32 category, time_t apply_time);
    void AddCreatureSpellCooldown(uint32 spellid);
    bool HasSpellCooldown(uint32 spell_id) const;
    bool HasCategoryCooldown(uint32 spell_id) const;

    bool HasSpell(uint32 spellID) const;

    bool UpdateEntry(uint32 entry, uint32 team=ALLIANCE, const CreatureData* data=NULL);
    bool UpdateStats(Stats stat);
    bool UpdateAllStats();
    void UpdateResistances(uint32 school);
    void UpdateArmor();
    void UpdateMaxHealth();
    void UpdateMaxPower(Powers power);
    void UpdateAttackPowerAndDamage(bool ranged = false);
    void UpdateDamagePhysical(WeaponAttackType attType);
    uint32 GetCurrentEquipmentId() { return m_equipmentId; }
    void SetCurrentEquipmentId(uint32 entry) { m_equipmentId = entry; }
    float GetSpellDamageMod(int32 Rank);

    VendorItemData const* GetVendorItems() const;
    uint32 GetVendorItemCurrentCount(VendorItem const* vItem);
    uint32 UpdateVendorItemCurrentCount(VendorItem const* vItem, uint32 used_count);

    TrainerSpellData const* GetTrainerSpells() const;

    CreatureInfo const *GetCreatureInfo() const { return m_creatureInfo; }
    CreatureData const *GetCreatureData() const { return m_creatureData; }
    CreatureDataAddon const* GetCreatureAddon() const;

    std::string GetAIName() const;
    std::string GetScriptName() const;
    uint32 GetScriptId() const;

    void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); }
    void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId,language,TargetGuid); }
    void TextEmote(int32 textId, uint64 TargetGuid, bool IsBossEmote = false) { MonsterTextEmote(textId,TargetGuid,IsBossEmote); }
    void Whisper(int32 textId, uint64 receiver, bool IsBossWhisper = false) { MonsterWhisper(textId,receiver,IsBossWhisper); }
    void YellToZone(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYellToZone(textId,language,TargetGuid); }

    // override WorldObject function for proper name localization
    const char* GetNameForLocaleIdx(LocaleConstant locale_idx) const;

    void setDeathState(DeathState s);                   // override virtual Unit::setDeathState
    bool FallGround();

    bool LoadFromDB(uint32 guid, Map *map);
    void SaveToDB();
    // overwrited in Pet
    virtual void SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask);
    virtual void DeleteFromDB();                        // override in Pet

    Loot loot;
    bool lootForPickPocketed;
    bool lootForBody;
    Player *GetLootRecipient() const;
    Group *GetLootRecipientGroup() const;
    bool hasLootRecipient() const { return m_lootRecipient || m_lootRecipientGroup; }
    bool isTappedBy(Player *player) const;                          // return true if the creature is tapped by the player or a member of his party.

    void SetLootRecipient (Unit* unit);
    void AllLootRemovedFromCorpse();

    uint16 GetLootMode() { return m_LootMode; }
    bool HasLootMode(uint16 lootMode) { return m_LootMode & lootMode; }
    void SetLootMode(uint16 lootMode) { m_LootMode = lootMode; }
    void AddLootMode(uint16 lootMode) { m_LootMode |= lootMode; }
    void RemoveLootMode(uint16 lootMode) { m_LootMode &= ~lootMode; }
    void ResetLootMode() { m_LootMode = LOOT_MODE_DEFAULT; }

    SpellEntry const *reachWithSpellAttack(Unit *pVictim);
    SpellEntry const *reachWithSpellCure(Unit *pVictim);

    uint32 m_spells[CREATURE_MAX_SPELLS];
    CreatureSpellCooldowns m_CreatureSpellCooldowns;
    CreatureSpellCooldowns m_CreatureCategoryCooldowns;
    uint32 m_GlobalCooldown;

    bool canStartAttack(Unit const* u, bool force) const;
    float GetAttackDistance(Unit const* pl) const;

    void SendAIReaction(AiReaction reactionType);

    Unit* SelectNearestTarget(float dist = 0) const;
    Unit* SelectNearestTargetInAttackDistance(float dist = 0) const;

    void DoFleeToGetAssistance();
    void CallForHelp(float fRadius);
    void CallAssistance();
    void SetNoCallAssistance(bool val) { m_AlreadyCallAssistance = val; }
    void SetNoSearchAssistance(bool val) { m_AlreadySearchedAssistance = val; }
    bool HasSearchedAssistance() { return m_AlreadySearchedAssistance; }
    bool CanAssistTo(const Unit* u, const Unit* enemy, bool checkfaction = true) const;
    bool _IsTargetAcceptable(const Unit* target) const;

    MovementGeneratorType GetDefaultMovementType() const { return m_defaultMovementType; }
    void SetDefaultMovementType(MovementGeneratorType mgt) { m_defaultMovementType = mgt; }

    // for use only in LoadHelper, Map::Add Map::CreatureCellRelocation
    Cell const& GetCurrentCell() const { return m_currentCell; }
    void SetCurrentCell(Cell const& cell) { m_currentCell = cell; }

    void RemoveCorpse(bool setSpawnTime = true);
    bool isDeadByDefault() const { return m_isDeadByDefault; };

    void ForcedDespawn(uint32 timeMSToDespawn = 0);

    time_t const& GetRespawnTime() const { return m_respawnTime; }
    time_t GetRespawnTimeEx() const;
    void SetRespawnTime(uint32 respawn) { m_respawnTime = respawn ? time(NULL) + respawn : 0; }
    void Respawn(bool force = false);
    void SaveRespawnTime();

    uint32 GetRespawnDelay() const { return m_respawnDelay; }
    void SetRespawnDelay(uint32 delay) { m_respawnDelay = delay; }

    float GetRespawnRadius() const { return m_respawnradius; }
    void SetRespawnRadius(float dist) { m_respawnradius = dist; }

    // Linked Creature Respawning System
    time_t GetLinkedCreatureRespawnTime() const;
    const CreatureData* GetLinkedRespawnCreatureData() const;

    uint32 m_groupLootTimer;                            // (msecs)timer used for group loot
    uint32 lootingGroupLowGUID;                         // used to find group which is looting corpse

    void SendZoneUnderAttackMessage(Player* attacker);

    void SetInCombatWithZone();

    bool hasQuest(uint32 quest_id) const;
    bool hasInvolvedQuest(uint32 quest_id)  const;

    bool isRegeneratingHealth() { return m_regenHealth; }
    virtual uint8 GetPetAutoSpellSize() const { return MAX_SPELL_CHARM; }
    virtual uint32 GetPetAutoSpellOnPos(uint8 pos) const
    {
        if (pos >= MAX_SPELL_CHARM || m_charmInfo->GetCharmSpell(pos)->GetType() != ACT_ENABLED)
            return 0;
        else
            return m_charmInfo->GetCharmSpell(pos)->GetAction();
    }

    void SetHomePosition(float x, float y, float z, float o) { m_homePosition.Relocate(x, y, z, o); }
    void SetHomePosition(const Position &pos) { m_homePosition.Relocate(pos); }
    void GetHomePosition(float &x, float &y, float &z, float &ori) { m_homePosition.GetPosition(x, y, z, ori); }
    Position GetHomePosition() { return m_homePosition; }

    uint32 GetGlobalCooldown() const { return m_GlobalCooldown; }

    uint32 GetWaypointPath(){return m_path_id;}
    void LoadPath(uint32 pathid) { m_path_id = pathid; }

    uint32 GetCurrentWaypointID(){return m_waypointID;}
    void UpdateWaypointID(uint32 wpID){m_waypointID = wpID;}

    void SearchFormation();
    CreatureGroup *GetFormation() {return m_formation;}
    void SetFormation(CreatureGroup *formation) {m_formation = formation;}

    Unit *SelectVictim();
    void SetDeadByDefault (bool death_state) {m_isDeadByDefault = death_state;}

    void SetDisableReputationGain(bool disable) { DisableReputationGain = disable; }
    bool IsReputationGainDisabled() { return DisableReputationGain; }
    bool IsDamageEnoughForLootingAndReward() const { return m_PlayerDamageReq == 0; }
    void LowerPlayerDamageReq(uint32 unDamage)
    {
        if (m_PlayerDamageReq)
            m_PlayerDamageReq > unDamage ? m_PlayerDamageReq -= unDamage : m_PlayerDamageReq = 0;
    }
    void ResetPlayerDamageReq() { m_PlayerDamageReq = GetHealth() / 2; }
    uint32 m_PlayerDamageReq;

    void SetOriginalEntry(uint32 entry) { m_originalEntry = entry; }

    static float _GetDamageMod(int32 Rank);

    float m_SightDistance, m_CombatDistance;

    void SetGUIDTransport(uint32 guid) { guid_transport=guid; }
    uint32 GetGUIDTransport() { return guid_transport; }

    void FarTeleportTo(Map* map, float X, float Y, float Z, float O);
protected:
    bool CreateFromProto(uint32 guidlow, uint32 Entry, uint32 vehId, uint32 team, const CreatureData *data = NULL);
    bool InitEntry(uint32 entry, uint32 team=ALLIANCE, const CreatureData* data=NULL);

    // vendor items
    VendorItemCounts m_vendorItemCounts;

    void _RealtimeSetCreatureInfo();

    static float _GetHealthMod(int32 Rank);

    uint32 m_lootMoney;
    uint64 m_lootRecipient;
    uint32 m_lootRecipientGroup;

    /// Timers
    time_t m_corpseRemoveTime;                          // (msecs)timer for death or corpse disappearance
    time_t m_respawnTime;                               // (secs) time of next respawn
    uint32 m_respawnDelay;                              // (secs) delay between corpse disappearance and respawning
    uint32 m_corpseDelay;                               // (secs) delay between death and corpse disappearance
    float m_respawnradius;

    ReactStates m_reactState;                           // for AI, not charmInfo
    void RegenerateMana();
    void RegenerateHealth();
    void Regenerate(Powers power);
    MovementGeneratorType m_defaultMovementType;
    Cell m_currentCell;                                 // store current cell where creature listed
    uint32 m_DBTableGuid;                               ///< For new or temporary creatures is 0 for saved it is lowguid
    uint32 m_equipmentId;

    bool m_AlreadyCallAssistance;
    bool m_AlreadySearchedAssistance;
    bool m_regenHealth;
    bool m_AI_locked;
    bool m_isDeadByDefault;

    SpellSchoolMask m_meleeDamageSchoolMask;
    uint32 m_originalEntry;

    Position m_homePosition;

    bool DisableReputationGain;

    CreatureInfo const* m_creatureInfo;                 // in difficulty mode > 0 can different from sObjectMgr.::GetCreatureTemplate(GetEntry())
    CreatureData const* m_creatureData;

    uint16 m_LootMode;                                  // bitmask, default LOOT_MODE_DEFAULT, determines what loot will be lootable
    uint32 guid_transport;

    bool isVisibleForInState(WorldObject const* seer) const;
private:
    //WaypointMovementGenerator vars
    uint32 m_waypointID;
    uint32 m_path_id;

    //Formation var
    CreatureGroup *m_formation;
    bool TriggerJustRespawned;
};

class AssistDelayEvent : public BasicEvent
{
public:
    AssistDelayEvent(const uint64& victim, Unit& owner) : BasicEvent(), m_victim(victim), m_owner(owner) { }

    bool Execute(uint64 e_time, uint32 p_time);
    void AddAssistant(const uint64& guid) { m_assistants.push_back(guid); }
private:
    AssistDelayEvent();

    uint64            m_victim;
    std::list<uint64> m_assistants;
    Unit&             m_owner;
};

class ForcedDespawnDelayEvent : public BasicEvent
{
public:
    ForcedDespawnDelayEvent(Creature& owner) : BasicEvent(), m_owner(owner) { }
    bool Execute(uint64 e_time, uint32 p_time);

private:
    Creature& m_owner;
};

#endif
